<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!--
===================================================================================
 *  Copyright by KNIME AG, Zurich, Switzerland
 *  Website: http://www.knime.com; Email: contact@knime.com
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License, Version 3, as
 *  published by the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, see <http://www.gnu.org/licenses>.
 *
 *  Additional permission under GNU GPL version 3 section 7:
 *
 *  KNIME interoperates with ECLIPSE solely via ECLIPSE's plug-in APIs.
 *  Hence, KNIME and ECLIPSE are both independent programs and are not
 *  derived from each other. Should, however, the interpretation of the
 *  GNU GPL Version 3 ("License") under any applicable laws result in
 *  KNIME and ECLIPSE being a combined program, KNIME AG herewith grants
 *  you the additional permission to use and propagate KNIME together with
 *  ECLIPSE with only the license terms in place for ECLIPSE applying to
 *  ECLIPSE and the GNU GPL Version 3 applying for KNIME, provided the
 *  license terms of ECLIPSE themselves allow for the respective use and
 *  propagation of ECLIPSE together with KNIME.
 *
 *  Additional permission relating to nodes for KNIME that extend the Node
 *  Extension (and in particular that are based on subclasses of NodeModel,
 *  NodeDialog, and NodeView) and that only interoperate with KNIME through
 *  standard APIs ("Nodes"):
 *  Nodes are deemed to be separate and independent programs and to not be
 *  covered works.  Notwithstanding anything to the contrary in the
 *  License, the License does not apply to Nodes, you are not required to
 *  license Nodes under the License, and you are granted a license to
 *  prepare and propagate Nodes, in each case even if such Nodes are
 *  propagated with or for interoperation with KNIME.  The owner of a Node
 *  may freely choose the license terms applicable to such Node, including
 *  when such Node is propagated with or for interoperation with KNIME.
===================================================================================
-->
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>KNIME Visualization Framework</title>
<link rel=stylesheet " type="text/css"
  href="../../../../../../stylesheet_knime.css" />
</head>
<body>
<h1>KNIME Visualization Framework</h1>
<p>
The KNIME visualization framework supports an easy-to-use implementation of 
visualizations. The following sections provide an introduction into this 
framework (<a href="#overview">Overview</a>, <a href="#framework">Framework</a>) 
and links to already existing views (<a href="#impl">Implementations</a>).
</p>


<h2><a name="overview">Overview</a></h2>
<p>
The basic elements of the visualization framework is a so-called plotter. A 
plotter consists of four components:</p>
<ul>
<li>the plotter itself,</li>
<li>an embedded scroll pane (which is not visible and acessible to deriving classes),</li>
<li>a drawing pane, where the actual drawing is done</li>
<li>and the properties panel which provides interactive control elements for the view.</li>
</ul>
Illustration 1 displays the arrangement of these components.
<img src="overviewPic.png" alt="The combination of the above listet plotter elements" />
<p>
In the following the scroll pane is ignored since it is transparent to the user.
The remaining three components follow the Model-View-Controller pattern. 
</p>

<h3>Plotter</h3>
<p>
The plotter acts as the controller holding the drawing pane and the properties, 
translating the model data into a visual model for the drawing pane and 
forwarding changes in the properties to the drawing pane.
The plotter provides a default constructor, where the adequate drawing pane and 
properties are initialized and, where it makes sense, the plotter provides a 
constructor where the drawing pane and the properties are passed allowing to 
freely combine the components of the plotter. 
</p>

<h3>DrawingPane</h3> 
<p>
The drawing pane is the view and simply displays the already mapped data which 
has to be set by the plotter. In contrast to the hiliting, which is done by the 
plotter, the administration of selected elements might be done by the drawing pane. 
In general it is recommended to keep the drawing pane as simple as possible and 
do the logic in the plotter.
</p>

<h3>Properties</h3>
<p> 
The properties are organized in tabs to allow different combinations of property 
elements. The constructor simply instantiates the necessary tabs and add them 
to the property panel. Furthermore it has to provide access to the control 
elements in the tabs, since the plotter normally registers the listeners to the 
property control elements. 
</p>

<h3>Axes (optional)</h3>
<p>
A plotter may have a X (horizontal) axis and/or a Y (vertical) axis. They can 
be nominal or numeric whereby the latter may consist of integer or double values only. 


<h2><a name="framework">Framework</a></h2>
<p>
The abstract visualization framework is organized in more or less three layers 
where each layer provides more functionality. Illustration 2 gives a quick overview 
over the three abstract layers, which are described in the following.
</p>

<img src="overviewClassDiagram.png" alt="Components of the hierarchy described so far" />

<h4>AbstractPlotter</h4>
<p>
The core of the visualization framework is the AbstractPlotter. It provides all 
core functionality common to all plotters in the visualization framework, i.e.</p>
<ul>
<li>selection,</li>
<li>zooming and</li>
<li>moving the zoomed drawing pane.</li>
</ul>
<p>
The zooming, moving and resizing is all done in the abstract plotter. Since the 
selection depends on the displayed elements the selection mouse events are 
forwarded to the methods</p>
<pre>
selectClickedElement(Point p)
selectElementsIn(Rectangle r)
clearSelection()
</pre>
<p>
The AbstractPlotter is also responsible for the HiLiting. It holds a 
HiLiteHandler which is accessible via the delegate methods</p>
<pre>
delegateAddHiLiteListener
delegateGetHiLiteKeys
delegateHiLite
delegateIsHiLite
delegateRemoveAllHiLiteListener
delegateRemoveHiLiteListener
delegateUnHiLite
delegateUnHiLiteAll
</pre>
<p>
Since the hiliting depends on the underlying elements the HiLiteListener methods are abstract:</p>
<pre>
hiLite
hiLiteSelected
unHiLite
unHiLiteSelected
</pre>
<p>
The most important abstract methods of the AbstractPlotter are</p>
<pre>
updatePaintModel and
updateSize
</pre>
<p>
In the updatePaintModel a new model is available: new selection of columns, 
new underlying dataset or whatever and the mapping of all data has to be done, 
properties have to be updated and so on. In updateSize only the size of the 
plotter has changed and only the mapping has to be re-calculated.
The mapping is done with the help of the axes. An axis holds a coordinate which 
is responsible for the mapping from domain values to mapped values. A coordinate 
is created with a DataColumnSpec (numeric columns must contain the lower and 
upper bound, nominal columns must contain the possible values)</p>
<pre>
Coordinate.createCoordinate(DataColumnSpec colSpec)
</pre>
<p>
Other possibilities to create the coordinates are:</p>
<pre>
createXCoordinate(double min, double max)
createXCoordinate(int min, int max)
createNominalXCoordinate(Set&lt;DataCell&gt; possibleValues)
</pre>
<p>
Same methods are available for the y axis.

The mapped value can be retrieved with</p>
<pre>
getMappedXValue(DataCell domainValue)
getMappedYValue(DataCell domainValue)
</pre>

<p>
The AbstractPlotter itself doesn't create any axes or coordinates but provides 
all functionality to do so. Still unanswered is the question how the plotter can 
access the data to visualize, especially how the connection to the underlying 
NodeModel is realized. For this purpose a new interface DataProvider was introduced. 
The DataProvider has one method:</p>
<pre>
getDataArray(int index)
</pre>
<p>
A NodeModel implementing this interface should convert the input data into a 
DataArray and return it in this method. The index allows several different data 
arrays , e.g. from different inports, in the plotter to be visualized.
Even if your node creates a visualization model of the data which doesn't fit 
into a DataArray and there is no need to implement the DataProvider interface, 
the way how NodeModel, NodeView and Plotter are connected should be the same and is 
described in the following.
</p>

<img src="node_plotter_rel.png" alt="Relationship between NodeModel, NodeView and Plotter" />

<p>
The NodeModel generates the visualization model from the incoming data. 
The NodeView, which &quot;knows&quot; the NodeModel and the Plotter should pass 
the visualization model from the NodeModel (which for this purpose has to 
provide a getter) to the plotter (which must provide a setter). Furthermode, 
each NodeView instance should have its own plotter instance, since graphical 
components can not be shared. The best way to realize this is to pass a plotter 
instance to the NodeView's constructor and in the NodeFactory#getNodeView 
create a new NodeView with a new Plotter.
</p>

<h4>AbstractDrawingPane</h4>
<p>
As pointed out above the drawing pane simply draws the mapped elements, hence, 
the single abstract method to implement is</p>
<pre>
paintContent(Graphics g)
</pre>
<p>
This means that the data structures to be visualized have to be stored in the drawing pane. 
</p>

<h4>AbstractProperties</h4>
<p>
The AbstractProperties consists of the default tab only, i.e. a selection of 
the mouse mode (Selection, Zooming, Moving), a fit to screen button and a 
possibility to change the background color of the drawing pane. Normally, you 
would extend the properties you need, call super() in the constructor and then 
add your own tab.
</p>

<h4>BasicPlotter</h4>
<p>
The idea behind the BasicPlotter is to provide a small fraction of the 
functionality known from &quot;R&quot; or &quot;GnuPlot&quot;. If you have 
some basic elements, such as lines, ellipses, rectangles, you want to add to 
your view you can use the BasicPlotter.</p>
<pre>
addLine(double[] yValues, Color color, Stroke stroke)
addLine(double[] xValues, double[] yValues, Color color, Stroke stroke)
addRectangle(double x, double y, int width, int height, Color color, Stroke stroke, boolean filled)
addEllipse(double xCenter, double yCenter, double width, double height, Color color, Stroke stroke, boolean filled)
</pre>
<p>
The usage of the BasicPlotter methods only makes sense, if you know the domain 
values of the elements but have no clue about the mapped values. One example is 
a ScatterPlot where you want to add a regression line. Here you only know the 
domain values of the line and you can simply add a line to the plotter with the 
domain values. The BasicPlotter will map the domain values to the drawing 
pane&rsquo;s size. If you set preserve = true in the AbstractPlotter the 
existing ranges of the coordinates won't be adapted. If you set preserve to 
false, the ranges will be adapted if, fior example, the added rectangle is 
larger than the existing range of the coordinates.
Another possibility is to add a DataArray which will be visualized by a line 
connecting all values in the columns, where the row number is the x axis and 
the value of the column is painted at the y axis.
addLine(DataArray data, int columnIndex, Color color, Stroke stroke)
</p>
<p>
If you want to add a specific element to the basic plotter you can extend the 
BasicDrawingElement or the Basic2DDrawingElement (described below) with</p>

<pre>
addBasicDrawingElement(BasicDrawingElement element)
</pre>

<h4>BasicDrawingElement and Basic2DDrawingElement</h4>
<p>
A BasicDrawingElement consists of a number of domain values and the referring mapped points, 
a color and a stroke. Whenever the size is changed, the BasicPlotter takes the 
domain values and maps them to the current drawing pane size. How 
the BasicDrawingElement is actually painted (depending on the given points) is 
defined in the paint method which is abstract. The Basic2DDrawingElement extends 
the BasicDrawingElement by holding a flag, whether the form should be filled or not.
Thus, if you want to add, for example, a triangle you have to extend the B
asic2DDrawingElement; then assert that the given points are the left corner, 
the top and the right corner and define the paint method to connect the points 
or fill the shape.
</p>

<h4>BasicDrawingPane</h4>
<p>
You can add BasicDrawingElements to the BasicDrawingPane, get them and clear the 
BasicDrawingElements with the following methods:</p>
<pre>
addDrawingElement(BasicDrawingElement element)
getDrawingElements()
clearPlot()
</pre>

<h4>TwoColumnPlotter</h4>
<p>
The TwoColumnPlotter comes with all functionality necessary if you want to 
display 2 columns of your data. The TwoColumnProperties consist of two select 
boxes for the columns and an adjustment for the ranges of the columns. 
The TwoColumnPlotter listens to the properties and does the appropriate changes 
and notifications for all extending classes. Thus, if you extend from the 
TwoColumnPlotter and your Properties extend from the TwoColumnProperties you 
just have to implement the updatePaintModel and updateSize methods. The 
updatePaintModel is called, whenever the column selection changes.
</p>

<h4>Properties</h4>
<p>
As already mentioned, the Properties are organized in tabs, i.e. for each 
specific plotter property exist a tab which can easily be reused if the same 
adjustments are needed for your implementation. For example the ScatterMatrix 
uses the same properties for the appearance but obviously a different column 
selection mechanism.
</p>

<h4>DefaultVisualizationNode</h4>
<p>
The DefaultVisualizationNode provides a convenient way to embed a plotter into 
a KNIME Node. The DefaultVisualizationNodeModel stores the input data at 
port 0 into a data array and returns it with getDataArray(int index). 
It implements the load and save internals where it saves/loads exactly this 
data array. The DefaultVisualizationNode also has a dialog where the maximum 
number of rows to visualize could be specified. Default values 2.500. 
In addition all columns are excluded, which are not compatible with DoubleValue 
or NominalValue and NominalValues with no or more than 60 possible values.
</p>
<p>
The DefaultVisualizationNodeView comes with two different constructors, each 
taking a plotter as an argument:</p>
<pre>
DefaultVisualizationNodeView(NodeModel model, AbstractPlotter plotter)
DefaultVisualizationNodeView(NodeModel model, AbstractPlotter plotter, String title)
</pre>
<p>
The difference between the two constructors is, that the latter places the 
plotter in a tab with the passes title. You may add additional plotters to the 
NodeView using</p>
<pre>
addVisualization(AbstractPlotter plotter, String title)
</pre>
<p>
which puts the passed plotter in a tab with the passed title and adds it to the NodeView.
The DefaultVisualizationNodeView maintains the plotters, i. e. sets the model as 
the DataProvider, gets the HiliteHandler from the model and adds it to the plotter, etc. 
If you have a simple plotter which visualizes the data from one inport you can 
use the DefaultVisualizationNode by simply writing your own NodeFactory and 
return the DefaultNodeModel as the NodeModel and the DefaultVisualizationNodeView 
with your plotter as the NodeView.
</p>
<p>
If the DefaultVisualizationNodeView doesn't fit your needs you have to take care that:</p>
<ul>
<li>Each NodeView has its own plotter instances: visual components can not be shared!</li>
<li>If you want to support hiliting the hilite menu has to be set in the NodeView's constructor with:
<pre>
getJMenuBar().add(plotter.getHiLiteMenu());
</pre>
</li>

<li>In the modelChanged the following is done:
<ol>
<li>reset plotter</li> 
<li>setHiliteHandler</li>
<li>setDataProvider</li>
<li>updatePaintModel</li>
</ol>
</li>
</ul>


<h2><a name="impl">Implementations</a></h2>
There are a couple of implementations of the plotter in KNIME, which are listet below:
<ul>
<li>LinePlotter: <a href="../line/package-summary.html">org.knime.base.node.viz.plotter.line.*</a></li>
<li>ScatterPlotter: <a href="../scatter/package-summary.html">org.knime.base.node.viz.plotter.scatter.*</a></li>
<li>ScatterMatrixPlotter: <a href="../scattermatrix/package-summary.html">org.knime.base.node.viz.plotter.scattermatrix.*</a></li>
<li>ParallelCoordinatePlotter: <a href="../parcoord/package-summary.html">org.knime.base.node.viz.plotter.parcoord.*</a></li>
<li>BoxPlotter: <a href="../box/package-summary.html">org.knime.base.node.viz.plotter.box.*</a></li>
<li>DendrogramPlotter: <a href="../dendrogram/package-summary.html">org.knime.base.node.viz.plotter.dendrogram.*</a></li>
</ul>
</body>
